/**
 * @class Ext.ux.MVC
 * Experimental Model View Controller class
 * @cfg {Object} name The MVC application name
 * @cfg {Object} config MVC application configs. Such as base URL.
 * @cfg {Object} models The models for the app
 * @cfg {Object} views The views for the app
 * @cfg {Object} controllers The event handlers for the app
 * @constructor
 * Create a new Ext MVC app
 * @param {Object} config The config object
 * 
 * @author collin.miller@scribestorm.com
 */


Ext.ux.MVC = function(config) {
	if (!config.name) {throw "Provide a name for your MVC app. Config options: name:String";}
	this.generateSkeleton(config.name);
	this.populateSkeleton(config);
	this.buildModels();
	Ext.onReady(this.bootViewport.createDelegate(this));
}

Ext.ux.MVC.prototype = {
	//private
	CONSTRUCTOR: 0,
	
	//private 
	CONFIG: 1,
	
	/**	
     * Generates an empty application skeleton. Ssets window[name] to the skeleton.
     * @param {name} name The name to use when creating the application
     */
	generateSkeleton: function(name) {
		window[name] = this;
		Ext.apply(this, {
			models:      {},
			views:       {},
			controllers: {},
			config: {}
		});
	},

	//private
	// fill in the app skeleton with user provided config
	populateSkeleton: function(config) {		
		Ext.apply(this, config);
		
/* Highly experimental and RoR specific */		
//		Ext.apply(skeleton.config, {
//			resource: {
//				site: this.config.site,
//				scope: this.app.models,
//				transport: Ext.ux.Rest.transport
//			}
//		});
	},
	
	//private
	// Iterates over all models.
	// If config for a model is a function the result of the function will be used
	// as the arguments for the constructor.
	buildModels: function(app, resourceConfig) {
		var slot, models = this.models, constructor, config;
		
/* Highly experimental and RoR specific */
//		Ext.each(models.resources||[],
//			function(resource) {
//				Resource(resource, resourceConfig);
//			});
		
		for (slot in models) { this.construct(models, slot); }
	},
	
	//private
	construct: function(scope, name) {
		var constructor = this.findConstructor(scope[name]),
			config = scope[name][this.CONFIG];

		if (typeof constructor === "function") {
			if (typeof config === "function") {
				scope[name] = new constructor(config.call(this));
			}
			else {
				scope[name] = new constructor(config);
			}
		}
//		else if (constructor === 'function') {
//			scope[name] = config.call(this);
//		}
	},
	
	//private
	findConstructor: function(constructor) {
		var selector = constructor[this.CONSTRUCTOR];


//		if (selector === 'function') {
//			return 'function';
//		}
//		else 
		if (selector && selector.constructor === String) {
			return Ext.delve(Ext, selector);
		}
		
		return selector;
	},
	
	//private
	bootViewport: function() {
		new Ext.Viewport({
			layout: 'border',
			plugins: {
				init: this.onViewportBoot.createDelegate(this)
			}
		});
	},
	
	//private
	onViewportBoot: function(viewport) {
		this.views.viewport = viewport;
		this.instantiateViews();
		this.applyControllers();
	},

	//private
	// Iterates over all views.
	// If config for a views is a function the result of the function will be used
	// as the arguments for the constructor.
	instantiateViews: function() {
		var slot, views = this.views;
			
		for (slot in views) {
			if (slot !== 'viewport') {
				this.construct(views, slot);
			}
		}
	},
	
	//private
	// Looks up named components in the views or models namespaces of the app.
	// Uses Obsevable#on to apply function to event.
	applyControllers: function() {
		var slot, component, componentToUse, event, eventName,
			controllers = this.controllers,
			models = this.models
			views  = this.views;
		
		if (controllers.constructor === Function) {controllers = controllers();}
		
		for (slot in controllers) {
			component = models[slot] || views[slot] || null;
			if (!component) { console.trace(); throw "Attempted to attach events to non-existant component: "+slot }
			else {
				for (event in controllers[slot]) {
					splitEvent = event.split(":");
					if (splitEvent.length == 1) {
						component.on(splitEvent[0], controllers[slot][event]);
					}
					else {
						Ext.delve(component, splitEvent[0]).on(splitEvent.pop(), controllers[slot][event])
					}
				}
			}
		}
	}
};

